from sly import Lexer, Parser

class CalcLexer(Lexer):
    tokens = { NAME, NUMBER, QE, NE, IF, BOOL, PRINT, INPUT}
    ignore = ' \t'
    # ignore_commit 
    literals = { '=', '+', '-', '*', '/', '(', ')' ,'{','}', ':',';','<','>'}

    # Tokens
    NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
    QE = "=="
    NE = "!="
    IF = "if"
    PRINT = "print"
    INPUT = "input"

    @_(r'\d+')
    def NUMBER(self, t):
        t.value = int(t.value)
        return t
    
    
    @_(r'(True)│(False)')
    def BOOL(self, t):
        t.value = bool(t.value)
        return t
    
    @_(r'\n+')
    def newline(self, t):
        self.lineno += t.value.count('\n')

    def error(self, t):
        print("Illegal character '%s'" % t.value[0])
        self.index += 1

class CalcParser(Parser):
    tokens = CalcLexer.tokens

    precedence = (
        ('right','IF'),
        ('left',';'),
        ('left','QE'),
        ('left', '+', '-'),
        ('left', '*', '/'),
        ('right', 'UMINUS'),
        ('right','PRINT','INPUT'),
        )

    def __init__(self):
        self.names = {'True':True,'False':False}

    @_('PRINT expr')
    def statement(self, p):
        print(p.expr)
        return
    
    
    @_('INPUT')
    def statement(self, p):
        return input()
    
    @_('IF expr ":" expr')
    def statement(self, p):
        if p.expr0 == True:
            return p.expr1
    
   
    @_('NAME "=" expr')
    def statement(self, p):
        self.names[p.NAME] = p.expr
        
    @_('expr QE expr')
    def statement(self, p):
        print(p.expr0 == p.expr1)
        return p.expr0 == p.expr1
    
    @_('expr NE expr')
    def statement(self, p):
        print(p.expr0 != p.expr1)
        return p.expr0 != p.expr1

    @_('expr')
    def statement(self, p):
        print(p.expr)

    @_('expr "+" expr')
    def expr(self, p):
        return p.expr0 + p.expr1

    @_('expr "-" expr')
    def expr(self, p):
        return p.expr0 - p.expr1

    @_('expr "*" expr')
    def expr(self, p):
        return p.expr0 * p.expr1

    @_('expr "/" expr')
    def expr(self, p):
        return p.expr0 / p.expr1

    @_('"-" expr %prec UMINUS')
    def expr(self, p):
        return -p.expr

    @_('"(" expr ")"')
    def expr(self, p):
        return p.expr

    @_('"{" expr "}"')
    def expr(self, p):
        return p.expr

    @_('expr ";" expr')
    def expr(self, p):
        print(p.expr0)
        return p.expr1


    @_('NUMBER')
    def expr(self, p):
        return p.NUMBER
    
    
    @_('BOOL')
    def expr(self, p):
        return p.BOOL
        
    @_('NAME')
    def expr(self, p):
        try:
            return self.names[p.NAME]
        except LookupError:
            print("Undefined name '%s'" % p.NAME)
            return 0

if __name__ == '__main__':
    lexer = CalcLexer()
    parser = CalcParser()
    while True:
        try:
            text = input('calc > ')
        except EOFError:
            break
        if text:
            parser.parse(lexer.tokenize(text))